package input.pilot;

import fileHandling.language.options.Controls;
import gameStates.absGamesStates.AbsIngameState;
import gameStates.absGamesStates.gui.AbsChatState;
import input.PlayerKeyInput;
import logic.common.player.Player;
import logic.items.ItemType;
import logic.nodes.MoveForwardController;
import logic.ships.hunter.Hunter;
import logic.weapons.WeaponType;

import com.jme.input.controls.GameControl;
import com.jme.input.controls.controller.ActionChangeController;
import com.jme.input.controls.controller.ControlChangeListener;
import com.jme.math.Vector3f;

/**
 * Implements a key-input-handler for a pilot-{@link Player}. It has {@link Binding}s to navigate a {@link Hunter}, 
 * to set the next target of the {@link Player} and to activate the {@link Hunter}'s boost.
 * 
 * @author Wasserleiche
 */
public class PilotKeyInput extends PlayerKeyInput {
	
	public static final float QUICK_BOOST_TIME = 0.5f;
	
	/** The {@link Hunter} that has to be controlled. */
	private Hunter hunter;
	
	private GameControl forward, backward, stepLeft, stepRight, nextTarget, boost, 
						fireMissile, fireHeatseaker, useCounterMeasures, useRepairKit, useShieldBattery, useEnergyCell, 
						toggleMissions, moveMissionLocation;
	private MoveForwardController moveForwardBack;
	private StrafeController moveLeftController;
	
	/**
	 * Constructs a new PilotKeyInput-object with the given {@link Hunter}. All {@link Binding}s and actions will +
	 * be set up here.
	 * @param hunter The {@link Hunter} that has to be controlled.
	 */
	public PilotKeyInput(Hunter hunter, AbsIngameState ingameState, AbsChatState chatState) {
		super(ingameState.getRootNode(), chatState, ingameState);
		
		this.hunter = hunter;
		if(hunter != null) {
			setKeyBindings();
			setKeyActions();
		}
	}
	
	/**
	 * Sets up all key-{@link Binding}s for the {@link Player}.
	 */
	private void setKeyBindings() {
		forward = registerKeyControl(Controls.Forward);
		backward = registerKeyControl(Controls.Break);
		stepLeft = registerKeyControl(Controls.Left);
		stepRight = registerKeyControl(Controls.Right);
		
		nextTarget = registerKeyControl(Controls.Nearest_Target);
		boost = registerKeyControl(Controls.Activate_Boost);
		
		fireMissile = registerKeyControl(Controls.Fire_Missile);
		fireHeatseaker = registerKeyControl(Controls.Fire_Heatseaker);
		
		useCounterMeasures = registerKeyControl(Controls.Use_Counter_Measures);
		useRepairKit = registerKeyControl(Controls.Use_Repairkit);
		useShieldBattery = registerKeyControl(Controls.Use_Shieldbattery);
		useEnergyCell = registerKeyControl(Controls.Use_Energycell);
		
		moveMissionLocation = registerKeyControl(Controls.Move_To_Mission_Location);
		
		toggleMissions = registerKeyControl(Controls.Toggle_Mission);
	}
	
	/**
	 * Sets up all actions that shall be performed.
	 */
	private void setKeyActions() {
		float maxSpeed = hunter.getMaxForwardSpeed();
		float maxStrafe = hunter.getMaxStrafeSpeed();
		float strafeAcc = hunter.getStrafeAcceleration();
		float strafeBreak = hunter.getStrafeBreaking();
		float acc = hunter.getForwardAcceleration();
		float beaking = hunter.getStrafeBreaking();
		float boostSpeed = hunter.getMaxBoostSpeed();
		moveForwardBack = new MoveForwardController(hunter, forward, maxSpeed, boostSpeed, acc, backward, beaking);
		hunter.setMoveForwardController(moveForwardBack);
		moveLeftController = new StrafeController(hunter, stepLeft, maxStrafe, strafeAcc, stepRight, strafeBreak);
		hunter.setStrafeController(moveLeftController);
		
		ActionChangeController quickBoost = new ActionChangeController(forward, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				Player currentPlayer = hunter.getPilot();
				if(currentPlayer.isAlive()) {
					if(newValue == 1.0f) {
						if(time <= QUICK_BOOST_TIME) moveForwardBack.enableBoost(true);
					} else moveForwardBack.enableBoost(false);
				}
			}
		});
		hunter.addHunterFlightController(quickBoost);
		
		ActionChangeController setTarget = new ActionChangeController(nextTarget, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				Player currentPlayer = hunter.getPilot();
				if(newValue == 1.0f && currentPlayer.isAlive()) {
					Vector3f loc = hunter.getLocalTranslation();
					Hunter target = currentPlayer.getEnemyTeam().getNearestHunter(loc);
					if(target != null) currentPlayer.setCurrentTarget(target);
				}
			}
		});
		hunter.addHunterFlightController(setTarget);
		
		ActionChangeController setBoost = new ActionChangeController(boost, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && !moveForwardBack.isBoosting()) moveForwardBack.enableBoost(true);
				else if(newValue == 0f && moveForwardBack.isBoosting()) moveForwardBack.enableBoost(false);
			}
		});
		hunter.addHunterFlightController(setBoost);
		
		ActionChangeController setFireHeatseaker = new ActionChangeController(fireHeatseaker, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f) hunter.fireWeapons(getMouseDirection(), WeaponType.HeatSeeker);
			}
		});
		hunter.addHunterFlightController(setFireHeatseaker);
		
		ActionChangeController setFireMissile = new ActionChangeController(fireMissile, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f) hunter.fireWeapons(getMouseDirection(), WeaponType.Missile);
			}
		});
		hunter.addHunterFlightController(setFireMissile);
		
		ActionChangeController setUseCM = new ActionChangeController(useCounterMeasures, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f) hunter.useCounterMeasures();
			}
		});
		hunter.addHunterFlightController(setUseCM);

		addItemAction(useRepairKit, ItemType.Repair);
		addItemAction(useShieldBattery, ItemType.Shields);
		addItemAction(useEnergyCell, ItemType.Energy);
		
		ActionChangeController setMission = new ActionChangeController(toggleMissions, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f) 	hudState.getPilotHUD().toggleMissions();
			}
		});
		hunter.addHunterFlightController(setMission);
		
		ActionChangeController moveMissionController = new ActionChangeController(moveMissionLocation, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f) {
					hunter.removeResetRotController();
					if(hunter.getMoveToMissionController() == null) 
						hunter.setMoveToMissionController(new MoveToMissionController(hunter.getPilot()));
				}
			}
		});
		hunter.addHunterFlightController(moveMissionController);
	}
	
	private void addItemAction(GameControl gameControl, final ItemType itemType) {
		ActionChangeController itemAction = new ActionChangeController(gameControl, new ControlChangeListener() {
			@Override
			public void changed(GameControl control, float oldValue, float newValue, float time) {
				if(newValue == 1f && hunter.getItemsAmount(itemType) > 0) 
					hunter.useItem(itemType);
			}
		});
		hunter.addHunterFlightController(itemAction);
	}
}